﻿#include "encode.h"
#include <stddef.h>

#include <assert.h>
#include<string.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <memory.h>

#ifndef WIN32
#include <iconv.h>
#else
#include <windows.h>
#endif

#ifdef __cplusplus
extern "C"
{
#endif

#ifndef WIN32

int GB2312ToUTF8( char const *srcStr, char* desBuff, int desBuffLength)
{
    assert(strlen(srcStr)>0);
    size_t iLen = strlen(srcStr);
	size_t outLent = desBuffLength;

    iconv_t cd;
    cd = iconv_open("utf-8","gb2312");
    assert(cd != 0);
    int n=iconv(cd, (char **)&srcStr, &iLen, &desBuff, &outLent);
    iconv_close(cd);
    return n;
}

int UTF8ToGB2312( char const *srcStr, char* desBuff, int desBuffLength)
{
    assert(strlen(srcStr)>0);
    size_t iLen = strlen(srcStr);
	size_t outLent = desBuffLength;

    iconv_t cd;
    cd = iconv_open("gb2312","utf-8");
    assert(cd != 0);
    int n=iconv(cd, (char **)&srcStr, (size_t*)&iLen, &desBuff, &outLent);
    iconv_close(cd);
    return n;
}

#endif

#ifdef _WIN32
void utf8_to_gb(const char* src, char* dst, int len)
{
	int ret = 0;
	WCHAR* strA;
	int i = MultiByteToWideChar(CP_UTF8, 0, src, -1, NULL, 0);
	if (i <= 0) {
		printf("ERROR.");
		return;
	}
	strA = (WCHAR*)malloc(i * 2);
	MultiByteToWideChar(CP_UTF8, 0, src, -1, strA, i);
	i = WideCharToMultiByte(CP_ACP, 0, strA, -1, NULL, 0, NULL, NULL);
	if (len >= i) {
		ret = WideCharToMultiByte(CP_ACP, 0, strA, -1, dst, i, NULL, NULL);
		dst[i] = 0;
	}
	if (ret <= 0) {
		free(strA);
		return;
	}

	free(strA);
}

void gb_to_utf8(const char* src, char* dst, int len)
{
	int ret = 0;
	WCHAR* strA;
	int i = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
	if (i <= 0) {
		printf("ERROR.");
		return;
	}
	strA = (WCHAR*)malloc(i * 2);
	MultiByteToWideChar(CP_ACP, 0, src, -1, strA, i);
	i = WideCharToMultiByte(CP_UTF8, 0, strA, -1, NULL, 0, NULL, NULL);
	if (len >= i) {
		ret = WideCharToMultiByte(CP_UTF8, 0, strA, -1, dst, i, NULL, NULL);
		dst[i] = 0;
	}

	if (ret <= 0) {
		free(strA);
		return;
	}
	free(strA);
}
#else   //Linux
// starkwong: In iconv implementations, inlen and outlen should be type of size_t not uint, which is different in length on Mac
void utf8_to_gb(const char* src, char* dst, int len)
{
	int ret = 0;
	size_t inlen = strlen(src) + 1;
	size_t outlen = len;

	// duanqn: The iconv function in Linux requires non-const char *
	// So we need to copy the source string
	char* inbuf = (char *)malloc(len);
	char* inbuf_hold = inbuf;   // iconv may change the address of inbuf
	// so we use another pointer to keep the address
	memcpy(inbuf, src, len);

	char* outbuf = dst;
	iconv_t cd;
	cd = iconv_open("GBK", "UTF-8");
	if (cd != (iconv_t)-1) {
		ret = iconv(cd, &inbuf, &inlen, &outbuf, &outlen);
		if (ret != 0) {
			printf("iconv failed err: %s\n", strerror(errno));
		}

		iconv_close(cd);
	}
	free(inbuf_hold);   // Don't pass in inbuf as it may have been modified
}

void gb_to_utf8(const char* src, char* dst, int len)
{
	int ret = 0;
	size_t inlen = strlen(src) + 1;
	size_t outlen = len;

	// duanqn: The iconv function in Linux requires non-const char *
	// So we need to copy the source string
	char* inbuf = (char *)malloc(len);
	char* inbuf_hold = inbuf;   // iconv may change the address of inbuf
	// so we use another pointer to keep the address
	memcpy(inbuf, src, len);

	char* outbuf2 = NULL;
	char* outbuf = dst;
	iconv_t cd;

	// starkwong: if src==dst, the string will become invalid during conversion since UTF-8 is 3 chars in Chinese but GBK is mostly 2 chars
	if (src == dst) {
		outbuf2 = (char*)malloc(len);
		memset(outbuf2, 0, len);
		outbuf = outbuf2;
	}

	cd = iconv_open("UTF-8", "GBK");
	if (cd != (iconv_t)-1) {
		ret = iconv(cd, &inbuf, &inlen, &outbuf, &outlen);
		if (ret != 0)
			printf("iconv failed err: %s\n", strerror(errno));

		if (outbuf2 != NULL) {
			strcpy(dst, outbuf2);
			free(outbuf2);
		}

		iconv_close(cd);
	}
	free(inbuf_hold);   // Don't pass in inbuf as it may have been modified
}
#endif

#ifdef __cplusplus
} //end of extern "C" {
#endif
